package com.liliudong.pinkyponk.api.admin.filter;

import cn.hutool.jwt.JWTException;
import com.alibaba.fastjson2.JSONObject;
import com.liliudong.pinkyponk.core.constant.ResponseMessage;
import com.liliudong.pinkyponk.core.constant.SecurityConst;
import com.liliudong.pinkyponk.core.exception.PinkyPonkGloableException;
import com.liliudong.pinkyponk.security.exception.JwtExpiredException;
import com.liliudong.pinkyponk.security.exception.JwtNotVerifyException;
import com.liliudong.pinkyponk.security.util.JwtHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * AuthTokenFilter
 *
 * @author liliudong
 * @date 2022-05-27 15:00
 **/
@Slf4j
@RequiredArgsConstructor
public class AuthTokenFilter extends OncePerRequestFilter {

    private final JwtHelper jwtHelper;

    private final UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(@NotNull HttpServletRequest httpServletRequest,
                                    @NotNull HttpServletResponse httpServletResponse, @NotNull FilterChain filterChain)
            throws ServletException, IOException {
        String jwt = this.parseJwt(httpServletRequest);
        if (!StringUtils.hasText(jwt)) {
            throw new PinkyPonkGloableException(ResponseMessage.TOKEN_NOT_EXIST);
        }
        try {
            String userName = jwtHelper.parseToken(jwt);
            UserDetails userDetails = userDetailsService.loadUserByUsername(userName);
            UsernamePasswordAuthenticationToken authentication =
                    new UsernamePasswordAuthenticationToken(
                            userDetails, null, userDetails.getAuthorities());
            authentication.setDetails(
                    new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
            SecurityContextHolder.getContext().setAuthentication(authentication);
            filterChain.doFilter(httpServletRequest, httpServletResponse);
        } catch (JWTException | JwtNotVerifyException | JwtExpiredException e) {
            log.error(e.getMessage(), e);
            JSONObject responseBody = JSONObject.of("code", -1);
            responseBody.put("msg", e.getMessage());

            PrintWriter out = httpServletResponse.getWriter();
            httpServletResponse.setContentType("application/json");
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
            out.print(responseBody);
            out.flush();
        }
    }

    private String parseJwt(HttpServletRequest request) {
        String headerAuth = request.getHeader(SecurityConst.AUTHORIZATION);

        if (StringUtils.hasText(headerAuth) && headerAuth.startsWith(
                SecurityConst.BEARER + SecurityConst.SPACE)) {
            return headerAuth.substring(7);
        }

        return null;
    }
}
